package com.umeox.watch.moto.dataservice.services;


import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.NetworkOnMainThreadException;
import android.os.PowerManager;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;
import com.umeox.moto.common.log.Logger;
import com.umeox.moto.common.utils.NetUtils;
import com.umeox.moto.mqtt.base.AError;
import com.umeox.moto.mqtt.base.ARequest;
import com.umeox.moto.mqtt.base.AResponse;
import com.umeox.watch.location.proto.LocationProto;
import com.umeox.watch.moto.dataservice.BuildConfig;
import com.umeox.watch.moto.dataservice.DataProvider;
import com.umeox.watch.moto.dataservice.base.BaseApp;
import com.umeox.watch.moto.dataservice.constants.Constants;
import com.umeox.watch.moto.dataservice.constants.InternalConstant;
import com.umeox.watch.moto.dataservice.db.AppDataBase;
import com.umeox.watch.moto.dataservice.db.model.LocationInfo;
import com.umeox.watch.moto.dataservice.mqtt.interfaces.IPublishListener;
import com.umeox.watch.moto.dataservice.receiver.LocationReceiver;
import com.umeox.watch.moto.dataservice.utils.LocationHelper;
import com.umeox.watch.moto.dataservice.utils.LogUtils;
import com.umeox.watch.moto.dataservice.utils.Utils;

import java.lang.ref.WeakReference;
import java.util.Calendar;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 定位服务类
 * 采用IntentService处理多线程，IntentService接受定位请求
 * 在onHandlerIntent方法中，使用主线程Handler发送定位请求，并且阻塞当前onHandlerIntent线程
 * 直到定位完成，在主线程的Handler中通知释放阻塞线程，完成下一个请求
 * 在onCreate()方法打开WIFI，onDestroy()中关闭；GPS根据定位请求打开，onDestroy()中关闭
 * 如果是网络定位优先，会先判断上次定位完成时间是否与本次定位请求发送的时间相近，5秒内直接取上次定位结果
 */
public class LocationService extends IntentService implements LocationHelper.LocationCompleteListener {
    public static final int REQUEST_LOCATION = 0;
    public static final int MSG_LOCATION_COMPLETE = 1;
    public static final int MSG_TOAST_SHOW = 2;

    public static final String TAG = "Location-Service";


    private static final String ACTION_FREQUENCY_LOCATION = Constants.APPLICATION_ACTION + ".FREQUENCY_LOCATION";
    private static final String ACTION_CMD_LOCATION = Constants.APPLICATION_ACTION + ".CMD_LOCATION";
    private static final String ACTION_CALL_LOCATION = Constants.APPLICATION_ACTION + ".CALL_LOCATION";
    private static final String ACTION_LOWER_BATTERY = Constants.APPLICATION_ACTION + ".LOWER_BATTERY";
    private static final String ACTION_POWER_OFF_LOCATION = Constants.APPLICATION_ACTION + ".POWER_OFF_LOCATION";
    private static final String ACTION_PRAYER_LOCATION = Constants.APPLICATION_ACTION + ".PRAYER_LOCATION";
    private static final String ACTION_SOS2_LOCATION = Constants.APPLICATION_ACTION + ".SOS2_LOCATION";


    private static final String EXTRA_PRIORITY = "priority";
    private static final String EXTRA_CMD_ID = "cmdId";
    private static final String EXTRA_EID = "eid";
    private static final String EXTRA_REPORT_REASON_ATTR = "report_reason_attr";

    private final LockObject mLock = new LockObject();

    private Handler mHandler;
    private Context mContext;
    /**
     * 记录上次成功定位的结果
     */
    private LocationProto.LocationDetail lastLocation = null;

    private LocationHelper currentRequest;
    /**
     * 记录请求队列总数
     */
    private AtomicInteger requests = new AtomicInteger();
    /**
     * 定位请求队列
     */
    private BlockingQueue<Integer> requestQueue = new LinkedBlockingQueue<>();
    /**
     * 记录GPS请求在列队中的位置，队列中只允许有一个GPS定位请求
     */
    private volatile int gpsRequestIndex;
    /**
     * 定位请求队列中，当前正在处理的请求
     */
    private volatile int currentRequestIndex;

    //标记WIFI&GPS是否为程序打开，如果是，定位完成需要关闭
    public boolean wifiEnabledByMyself = false;

    public boolean isResetLocationAlarm = false;

    public LocationService() {
        super(TAG);
    }


    /**
     * 频率自动定位
     *
     * @param ctx
     * @param locFreqId
     */
    public static void freqLocation(Context ctx, long locFreqId) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_FREQUENCY_LOCATION);
        intent.putExtra(InternalConstant.EXTRA_LOC_ID, locFreqId);
        ctx.startService(intent);
    }

    /**
     * SOS2位置定位
     *
     * @param ctx
     */
    public static void sos2Location(Context ctx, String eid) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_SOS2_LOCATION);
        intent.putExtra(EXTRA_EID, eid);
        ctx.startService(intent);
    }


    /**
     * 用户主动请求定位
     */
    public static void cmdReqLocation(Context ctx, String cmdId, int priority) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_CMD_LOCATION);
        intent.putExtra(EXTRA_CMD_ID, cmdId);
        intent.putExtra(EXTRA_PRIORITY, priority);
        ctx.startService(intent);
    }

    /**
     * 通话结束，请求定位
     *
     * @param ctx
     * @param reportReasonAttr 当上报原因为0，3，4时，赋值为空
     */
    public static void callEndedLocation(Context ctx, String reportReasonAttr) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_CALL_LOCATION);
        intent.putExtra(EXTRA_REPORT_REASON_ATTR, reportReasonAttr);
        ctx.startService(intent);
    }

    /**
     * 低点报警，请求定位
     */
    public static void lowBatteryLocation(Context ctx) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_LOWER_BATTERY);
        ctx.startService(intent);
    }

    /**
     * 关机请求定位
     *
     * @param ctx
     */
    public static void shutdownLocation(Context ctx) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_POWER_OFF_LOCATION);
        ctx.startService(intent);
    }

    /**
     * 祈祷请求定位
     *
     * @param ctx
     */
    public static void prayerLocation(Context ctx) {
        Intent intent = new Intent(ctx, LocationService.class);
        intent.setAction(ACTION_PRAYER_LOCATION);
        ctx.startService(intent);
    }

    public static final String TAG_SCAN_WIFI = "scan_wifi";

    @Override
    public void onCreate() {
        super.onCreate();
        Logger.i(TAG + ">>>>>>>>>>>>>>LocationService onCreate<<<<<<<<<<<<<<<<");
        LogUtils.saveLog(">>>>>>>>>>>>>>LocationService onCreate<<<<<<<<<<<<<<<<");
        HandlerThread thread = new HandlerThread("LocationService");
        thread.start();

        mHandler = new MainHandler(this);
        mContext = this.getApplicationContext();
        wifiEnabledByMyself = false;
        isResetLocationAlarm = false;

//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//            WorkManager.getInstance(BaseApp.getInstance()).cancelAllWorkByTag(TAG_SCAN_WIFI);
//            OneTimeWorkRequest scanWifiWorkRequest =
//                    new OneTimeWorkRequest.Builder(ScanWifiWork.class)
//                            // Additional configuration
//                            .setInitialDelay(25, TimeUnit.SECONDS)
//                            .addTag(TAG_SCAN_WIFI)
//                            .build();
//            WorkManager.getInstance(BaseApp.getInstance())
//                    .enqueueUniqueWork(TAG_SCAN_WIFI, ExistingWorkPolicy.REPLACE, scanWifiWorkRequest);
//        }
    }

    @Override
    public void onStart(Intent intent, int startId) {
        if (!DataProvider.isActivated()) {
            Logger.w(TAG + ">>>Device is not activated");
        }

        int priority = BuildConfig.LOCATION_PRIORITY;
        int reportReason = -1;
        long locFreqId = 0;
        String reqId = "";
        String sosEventId = "";
        String reportReasonAttr = "";

        if (ACTION_FREQUENCY_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.FREQUENCY_LOCATION_VALUE;
            locFreqId = intent.getLongExtra(InternalConstant.EXTRA_LOC_ID, 0);
            if (locFreqId > 0) {
                int locPriority = AppDataBase.getInstance().locationPeriodDao().queryLocPriorityById(locFreqId);
                if (locPriority > 1) {
                    priority = LocationProto.LocPriority.PRIORITY_NETWORK_VALUE;
                }
            }
        } else if (ACTION_LOWER_BATTERY.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.LOWER_BATTERY_VALUE;
            priority = LocationProto.LocPriority.PRIORITY_NETWORK_VALUE;
        } else if (ACTION_POWER_OFF_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.POWER_OFF_LOCATION_VALUE;
            priority = LocationProto.LocPriority.PRIORITY_NETWORK_VALUE;
        } else if (ACTION_CMD_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.CMD_LOCATION_VALUE;
            reqId = intent.getStringExtra(EXTRA_CMD_ID);
            int lp = intent.getIntExtra(EXTRA_PRIORITY, 0);
            if (lp == 1) {
                priority = LocationProto.LocPriority.PRIORITY_GPS_VALUE;
            }
        } else if (ACTION_CALL_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.CALL_LOCATION_VALUE;
            reportReasonAttr = intent.getStringExtra(EXTRA_REPORT_REASON_ATTR);
        } else if (ACTION_SOS2_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.SOS2_LOCATION_VALUE;
            priority = LocationProto.LocPriority.PRIORITY_GPS_VALUE;
            sosEventId = intent.getStringExtra(EXTRA_EID);
        } else if (ACTION_PRAYER_LOCATION.equals(intent.getAction())) {
            reportReason = LocationProto.LocReason.PRAYER_LOCATION_VALUE;
            priority = LocationProto.LocPriority.PRIORITY_GPS_VALUE;
        }

        if (reportReason > -1) {
            //定位列队中，同时只能有一个GPS定位(只有App请求定位才有GPS优先)请求，这里做处理
            //0为网络定位优先，1为GPS优先
            boolean added = false;
            if (priority == LocationProto.LocPriority.PRIORITY_GPS_VALUE && reportReason != LocationProto.LocReason.PRAYER_LOCATION_VALUE) {
                //GPS定位请求，判断列队没有GPS定位才入列 S12项目要求不管当前队列有没有GPS队列都需要将新的定位请求加入队列
//                if (gpsRequestIndex > 0) {
//                    Logger.w(TAG + ">>>队列中已经有GPS定位");
//                    mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "队列中已经有GPS定位"));
//                } else {
                    added = requestQueue.offer(requests.incrementAndGet());
                    if (added) {
                        Logger.w(TAG + ">>>第" + requests.get() + "个请求(GPS定位)插入队列成功！");
                        LogUtils.saveLog(TAG + ">>>第" + requests.get() + "个请求(GPS定位)插入队列成功！");
                        mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "第" + requests.get() + "个请求(GPS定位)插入队列成功！"));
                        gpsRequestIndex = requests.get();
                    }
//                }
            } else {
                //不是GPS定位，直接放入列队
                added = requestQueue.offer(requests.incrementAndGet());
                if (added) {
                    Logger.w(TAG + ">>>第" + requests.get() + "个请求(Network定位)插入队列成功！");
                    mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "第" + requests.get() + "个请求(Network定位)插入队列成功！"));
                }
            }

            if (added) {
                LocationProto.LocationDetail.Builder locBuilder = LocationProto.LocationDetail.newBuilder()
                        .setEventId(UUID.randomUUID().toString())
                        .setStartTime(Calendar.getInstance().getTimeInMillis())
                        .setLocReason(LocationProto.LocReason.forNumber(reportReason))
                        .setLocReasonAttr(reportReasonAttr)
                        .setReqId(reqId)
                        .setLocFreqId(locFreqId)
                        .setSosEventId(sosEventId)
                        .setLocPriority(priority);
                intent.putExtra("location_info_protobuf", locBuilder.build().toByteArray());
                super.onStart(intent, startId);
            }
        }
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        byte[] protobufs = intent.getByteArrayExtra("location_info_protobuf");
        LocationProto.LocationDetail.Builder locBuilder = null;
        try {
            locBuilder = LocationProto.LocationDetail.newBuilder().mergeFrom(protobufs);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (locBuilder != null) {
            //2秒内取不到就返回null,也可以用take方法，娶不到数据会阻塞
            Integer request = requestQueue.poll();
            currentRequestIndex = request != null ? request : 0;
            Logger.i(TAG + ">>>正在处理第" + currentRequestIndex + "个请求！");
            LogUtils.saveLog(TAG + ">>>正在处理第" + currentRequestIndex + "个请求！");
            mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "正在处理第" + currentRequestIndex + "个请求！"));
            //按频率定位GPS优先，其他都是网络定位优先
            //所以安频率定位不采用上次定位结果
            boolean needLoca;
            if (lastLocation != null) {
                //判断上次定位请求时间与这次定位请求时间相差多少秒，小于5秒直接用上次定位结果
                long reqTime = locBuilder.getStartTime();
                long lastReqTime = lastLocation.getStartTime();
                if (locBuilder.getLocPriority() == LocationProto.LocPriority.PRIORITY_GPS_VALUE
                        || reqTime - lastReqTime > 5000) {
                    needLoca = true;
                } else {
                    needLoca = false;
                    locBuilder
                            .setLat(lastLocation.getLat())
                            .setLng(lastLocation.getLng())
                            .setAccuracy(lastLocation.getAccuracy())
                            .setAddress(lastLocation.getAddress())
                            .setCellTower(lastLocation.getCellTower())
                            .addAllNearbyCellTowers(lastLocation.getNearbyCellTowersList())
                            .addAllWifiPoints(lastLocation.getWifiPointsList())
                            .setNetwork(lastLocation.getNetwork())
                            .setLocReasonAttr(lastLocation.getLocReasonAttr())
                            .setBattery(BaseApp.getInstance().getBatteryLevel())
                            .setEndTime(System.currentTimeMillis())
                            .setLocMode(lastLocation.getLocMode())
                            .setOrder(lastLocation.getOrder())
                            .setSpeed(lastLocation.getSpeed())
                            .setDirection(lastLocation.getDirection())
                            .setHeight(lastLocation.getHeight())
                            .setTemperature(lastLocation.getTemperature())
                            .setCharge(lastLocation.getCharge());
                }
            } else {
                needLoca = true;
            }

            if (needLoca) {
                //0为网络定位优先，1为GPS优先
                if (locBuilder.getLocPriority() == LocationProto.LocPriority.PRIORITY_NETWORK_VALUE
                        && locBuilder.getLocReason() != LocationProto.LocReason.POWER_OFF_LOCATION) {
                    //打开WIFI方法里面会阻塞线程
                    // 关机上报位置走LBS优先，不需要等待WIFI搜索
                    enableWIFI(true);
                }

                try {
                    currentRequest = LocationHelper.getHelper(LocationService.this);
                    currentRequest.setLocListener(this);
                    currentRequest.requestLocation(locBuilder);
                    if (currentRequest.isWorking()) {
                        await();
                    }
                    if (mLock.needLock()) {
                        await();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    onLocationFailed(locBuilder);
                }
            } else {
                Logger.d(TAG + ">>>采用上次定位结果");
                onLocationSuccess(locBuilder);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Logger.i(TAG + ">>>LocationService on bind");
        return null;
    }

    private void await() throws Exception {
        synchronized (mLock) {
            Logger.d(TAG + ">>>线程挂起，等待定位结果->" + Thread.currentThread().getName());
            LogUtils.saveLog(TAG + ">>>线程挂起，等待定位结果->" + Thread.currentThread().getName());
            mLock.lock();
        }
        Logger.i(TAG + ">>>第" + currentRequestIndex + "次请求处理完成.");
        mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "第" + currentRequestIndex + "次请求处理完成."));
    }

    private void notifyUnlock() {
        synchronized (mLock) {
            Logger.d(TAG + ">>>通知挂起线程定位完成->" + Thread.currentThread().getName());
            LogUtils.saveLog(TAG + ">>>通知挂起线程定位完成->" + Thread.currentThread().getName());
            mLock.unLock();
        }
    }

    @Override
    public void onDestroy() {
        Logger.i(TAG + ">>>>>>>>>>>>>>LocationService onDestroy<<<<<<<<<<<<<<<<");
        LogUtils.saveLog(TAG + ">>>>>>>>>>>>>>LocationService onDestroy<<<<<<<<<<<<<<<<");
        if (!isResetLocationAlarm) {
            resetLocationAlarm(0);
        }
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//            WorkManager.getInstance(BaseApp.getInstance()).cancelAllWorkByTag(TAG_SCAN_WIFI);
//        }
        disableWIFI();
        mHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }


    /**
     * 第一个位置定位成功
     *
     * @param locBuilder 定位结果
     */
    @Override
    public void onFirstLocationSuccess(LocationProto.LocationDetail.Builder locBuilder) {

    }

    /**
     * 定位完成业务逻辑，判断是否超出安全区域，判断是否需要上报位置
     *
     * @param locBuilder 定位结果
     */
    @Override
    public void onLocationSuccess(LocationProto.LocationDetail.Builder locBuilder) {
        //当前处理的队列中的请求为GPS定位，GPS定位完成，重置标记，可以往队列中继续添加GPS定位请求
        if (currentRequestIndex == gpsRequestIndex) {
            gpsRequestIndex = 0;
        }

        Logger.d(TAG + ">>>定位成功->" + Thread.currentThread().getName());
        LogUtils.saveLog(TAG + ">>>定位成功->" + Thread.currentThread().getName());
        lastLocation = locBuilder.build();
        LocationProto.LocReason locReason = locBuilder.getLocReason();
        boolean noReportLocationFlag = false;

        LocationInfo locationInfo = null;
        try {
            locationInfo = LocationInfo.mergeFromProto(lastLocation);
            locationInfo.setId(AppDataBase.getInstance().locationInfoDao().save(locationInfo));
        } catch (Exception e) {
            e.printStackTrace();
            noReportLocationFlag = true;
            LogUtils.saveLog(TAG + ">>>定位成功,数据插入本地数据库失败");
        }

        //发送广播修设置下次定位闹钟
        resetLocationAlarm(locBuilder.getEndTime() - locBuilder.getStartTime());
        //通知等待的线程，继续下一步操作
        //如果有上报位置，在网络请求回调完成释放

        if (noReportLocationFlag || locReason == LocationProto.LocReason.PRAYER_LOCATION) {
            notifyUnlock();
        } else {
            uploadLocationRecord(locReason, lastLocation, locationInfo);
        }
    }

    @Override
    public void onLocationFailed(LocationProto.LocationDetail.Builder locBuilder) {
        //当前处理的队列中的请求为GPS定位，GPS定位完成，重置标记，可以往队列中继续添加GPS定位请求
        if (currentRequestIndex == gpsRequestIndex) {
            gpsRequestIndex = 0;
        }

        Logger.d(TAG + ">>>定位失败->" + Thread.currentThread().getName());
        //定位失败需要修改闹钟
        resetLocationAlarm(locBuilder.getEndTime() - locBuilder.getStartTime());
        try {
            LocationProto.LocReason flag = locBuilder.getLocReason();
            LocationProto.LocationDetail locationDetail = locBuilder.build();
            LocationInfo locationInfo = LocationInfo.mergeFromProto(locationDetail);
            AppDataBase.getInstance().locationInfoDao().save(locationInfo);
            if (flag == LocationProto.LocReason.SOS_LOCATION //SOS定位失败也需要上报
                    || flag == LocationProto.LocReason.CALL_LOCATION //拔打电话定位失败也需要上报
                    || flag == LocationProto.LocReason.LOWER_BATTERY //低电定位失败也需要上报
                    || flag == LocationProto.LocReason.POWER_OFF_LOCATION) {//关机定位失败也需要上报
                uploadLocationRecord(locBuilder.getLocReason(), locationDetail, locationInfo);
            } else {
                //定位失败，不需要上报位置，直接退出等待进行下一个操作
                notifyUnlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
            notifyUnlock();
        }
    }

    /**
     * 上报定位结果
     */
    public void uploadLocationRecord(LocationProto.LocReason locReason, LocationProto.LocationDetail locationDetail, LocationInfo locationInfo) {
        if (locationDetail == null) {
            notifyUnlock();
            return;
        }
        /**
         * 网络定位很快就处理完，{@link #onHandleIntent(Intent)}业务代码都已经执行完毕，位置才开始上报
         * 在上报位置的时候再次判断是否需要上锁
         */
        mLock.needLock(!mLock.isLocked());
        Logger.d(TAG + ">>>开始上报位置");
        LogUtils.saveLog(TAG + ">>>开始上报位置");
        try {
            LocationProto.LocationDetail detail = LocationProto.LocationDetail.parseFrom(locationDetail.toByteArray());
            if (detail != null) {
                ApiService.uploadLocationInfo(locReason.getNumber(), detail, new LocationUploadCallBack(locationInfo));
            }
            if (locationDetail.getLocReason() == LocationProto.LocReason.POWER_OFF_LOCATION) {
                //关机定位完成需要发送广播，通知系统关机
                Intent intent = new Intent();
                intent.setAction(Constants.ACTION_LOCATION_COMPLETED);
                sendBroadcast(intent);
            }
        } catch (Exception e) {
            Logger.e("上报位置报错:" + e.getMessage());
            e.printStackTrace();

        }
        mHandler.sendEmptyMessage(LocationService.MSG_LOCATION_COMPLETE);
    }

    @Override
    public void onStateChange(String message) {
        if (mHandler != null) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_TOAST_SHOW, message));
        }
    }

    /**
     * 定位完成，发送广播设置下次定位闹钟
     *
     * @param cost 上次定位耗时
     */
    private synchronized void resetLocationAlarm(long cost) {
        Logger.d("定位耗时:" + cost / 1000 + "秒，计划下次频率定位时间");
        LogUtils.saveLog("定位耗时:" + cost / 1000 + "秒，计划下次频率定位时间");
        Intent intent = new Intent(mContext, LocationReceiver.class);
        intent.setAction(InternalConstant.ACTION_RESET_LOCATION_ALARM);
        intent.putExtra(LocationReceiver.EXTRA_OFFSET, cost);
        mContext.sendBroadcast(intent);
        isResetLocationAlarm = true;
    }

    public void enableWIFI(boolean wait4Scan) {
        // 判断wifi是否打开，未打开则自动打开
        final boolean isWifiEnabled = Utils.isWifiEnabled(mContext);
        if (!isWifiEnabled) {
            try {
                Logger.i(TAG + ">>>打开Wi-Fi.");
                NetUtils.setWifiEnabled(true);
                wifiEnabledByMyself = true;
            } catch (Exception e) {
                Logger.e(TAG + ">>>打开Wi-Fi失败:" + e.getMessage());
                mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "打开Wi-Fi失败:" + e.getMessage()));
            }
        }
        //if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            scanWifi(wait4Scan);
        //}
    }

    /**
     * 扫描附近wifi，会阻塞线程，不能在主线程调用该方法
     *
     * @param wait 是否等待扫描结果
     */
    public void scanWifi(boolean wait) {
        PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG + ":Wifi-Scan");
        wl.acquire(20000);

        WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (!wait) {
            wifiManager.startScan();
        } else {
            if (Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId()) {
                throw new NetworkOnMainThreadException();
            }
            // 使用定时器,每隔1秒获得一次信号强度值
            //当搜索到附近有可用的WIFI或者20秒后取消任务
            CountDownLatch downLatch = new CountDownLatch(1);
            final AtomicLong start = new AtomicLong();
            BroadcastReceiver mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    Logger.i(TAG + ">>>附近WIFI：" + wifiManager.getScanResults());
                    Logger.i(TAG + ">>>WIFI搜索耗时：" + (System.currentTimeMillis() - start.get()) / 1000 + "秒");
                    downLatch.countDown();
                }
            };
            registerReceiver(mReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
            try {
                if (wifiManager.startScan()) {
                    Logger.w(TAG + ">>>开始扫描附近WIFI");
                    start.set(System.currentTimeMillis());
                    downLatch.await(20L, TimeUnit.SECONDS);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                unregisterReceiver(mReceiver);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (wl.isHeld()) {
            wl.release();
        }
        Logger.w(TAG + ">>>扫描WIFI结束");
    }

    private void disableWIFI() {
        try {
            if (wifiEnabledByMyself) {
                NetUtils.setWifiEnabled(false);
                Logger.i(TAG + ">>>关闭WIFI");
                mHandler.sendMessage(mHandler.obtainMessage(LocationService.MSG_TOAST_SHOW, "关闭WIFI"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            Logger.e(TAG + ">>>关闭GPS和WIFI报错:" + e.getMessage());
        }
    }

    private static class MainHandler extends Handler {
        private WeakReference<LocationService> mOuter;

        MainHandler(LocationService service) {
            mOuter = new WeakReference<>(service);
        }

        @Override
        public void handleMessage(Message msg) {
            LocationService outer = mOuter.get();
            if (outer != null) {
                if (msg.what == REQUEST_LOCATION) {
                    outer.onHandleIntent((Intent) msg.obj);
                } else if (msg.what == MSG_LOCATION_COMPLETE) {
                    //释放线程
                    outer.notifyUnlock();
                } else if (msg.what == MSG_TOAST_SHOW) {
                    if (BuildConfig.DEBUG) {
                        Toast.makeText(BaseApp.getInstance(),msg.obj.toString(),Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    }

    private final class ServiceHandler extends Handler {

        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent) msg.obj);
            if (requestQueue.isEmpty()) {
                Logger.d(TAG + ">>>>>>>>>>>>>>所有定位请求都已处理完成<<<<<<<<<<<<<<<<");
                stopSelf();
            }
        }
    }

    public static class LockObject {
        private final AtomicBoolean locked = new AtomicBoolean(false);
        private boolean needLock;

        private boolean needLock() {
            return needLock;
        }

        private void needLock(boolean needLock) {
            this.needLock = needLock;
        }

        public boolean isLocked() {
            return locked.get();
        }

        public void lock() throws InterruptedException {
            if (locked.compareAndSet(false, true)) {
                super.wait(BuildConfig.LOCK_WAIT);
            }
        }

        public void unLock() {
            super.notify();
            locked.set(false);
        }
    }

    private static class LocationUploadCallBack implements IPublishListener {

        private LocationInfo mLocationInfo;

        public LocationUploadCallBack(LocationInfo locationInfo) {
            mLocationInfo = locationInfo;
        }

        @Override
        public void onSuccess(ARequest request, AResponse response) {
            Logger.d(TAG, "onSuccess:->" + response.data.toString());
            JSONObject jsonObject = JSONObject.parseObject(response.data.toString());
            int errCode = jsonObject.getIntValue("ERR_CODE");
            if (errCode == 0) {
                Logger.i("上传位置成功,更新本地数据库上传标记");
                LogUtils.saveLog("上传位置成功,更新本地数据库上传标记");
                mLocationInfo.setReportFlag(1);
                long result = AppDataBase.getInstance().locationInfoDao().update(mLocationInfo);
                Logger.i("本地数据库上传标记更新" + (result > 0 ? "成功" : "失败"));
                LogUtils.saveLog("本地数据库上传标记更新" + (result > 0 ? "成功" : "失败"));
            } else {
                Logger.e(TAG, "ERR_MSG:" + jsonObject.getIntValue("ERR_MSG"));
                LogUtils.saveLog("ERR_MSG:" + jsonObject.getIntValue("ERR_MSG"));
            }
        }

        @Override
        public void onFailure(ARequest request, Object message, AError error) {
            Logger.i("上传位置失败,reason:" + error.getMsg());
            LogUtils.saveLog("上传位置失败,reason:" + error.getMsg());
        }
    }
}
